home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmcd-1.4 / libdi.d / os_dec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  8.2 KB  |  379 lines

  1. /*
  2.  *   libdi - CD Audio Player Device Interface Library
  3.  *
  4.  *   Copyright (C) 1995  Ti Kan
  5.  *   E-mail: ti@amb.org
  6.  *
  7.  *   This program is free software; you can redistribute it and/or modify
  8.  *   it under the terms of the GNU General Public License as published by
  9.  *   the Free Software Foundation; either version 2 of the License, or
  10.  *   (at your option) any later version.
  11.  *
  12.  *   This program is distributed in the hope that it will be useful,
  13.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *   GNU General Public License for more details.
  16.  *
  17.  *   You should have received a copy of the GNU General Public License
  18.  *   along with this program; if not, write to the Free Software
  19.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  */
  21.  
  22. /*
  23.  *   DEC Ultrix and OSF/1 support
  24.  *
  25.  *   Contributing author: Matt Thomas
  26.  *   E-Mail: thomas@lkg.dec.com
  27.  *
  28.  *   This software module contains code that interfaces the CD player
  29.  *   application to the DEC Ultrix and DEC OSF/1 operating systems.
  30.  *   The term DEC, Ultrix and OSF/1 are used here for identification
  31.  *   purposes only.
  32.  */
  33.  
  34. #ifndef LINT
  35. static char *_os_dec_c_ident_ = "@(#)os_dec.c    5.7 94/12/28";
  36. #endif
  37.  
  38. #include "common.d/appenv.h"
  39. #include "common.d/util.h"
  40. #include "libdi.d/libdi.h"
  41. #include "libdi.d/scsipt.h"
  42.  
  43. #if ((defined(__alpha) && defined(__osf__)) || \
  44.      defined(ultrix) || defined(__ultrix)) && \
  45.     defined(DI_SCSIPT) && !defined(DEMO_ONLY)
  46.  
  47. extern appdata_t    app_data;
  48. extern bool_t        scsipt_notrom_error;
  49. extern FILE        *errfp;
  50.  
  51. STATIC int        pthru_fd = -1,    /* Passthrough device file desc */
  52.             bus = -1,
  53.             target = -1,
  54.             lun = -1;
  55.  
  56.  
  57. /*
  58.  * pthru_send
  59.  *    Build SCSI CDB and send command to the device.
  60.  *
  61.  * Args:
  62.  *    opcode - SCSI command opcode
  63.  *    addr - The "address" portion of the SCSI CDB
  64.  *    buf - Pointer to data buffer
  65.  *    size - Number of bytes to transfer
  66.  *    rsvd - The "reserved" portion of the SCSI CDB
  67.  *    length - The "length" portion of the SCSI CDB
  68.  *    param - The "param" portion of the SCSI CDB
  69.  *    control - The "control" portion of the SCSI CDB
  70.  *    rw - Data transfer direction flag (READ_OP or WRITE_OP)
  71.  *    prnerr - Whether an error message should be displayed
  72.  *         when a command fails
  73.  *
  74.  * Return:
  75.  *    TRUE - command completed successfully
  76.  *    FALSE - command failed
  77.  */
  78. bool_t
  79. pthru_send(
  80.     byte_t        opcode,
  81.     word32_t    addr,
  82.     byte_t        *buf,
  83.     word32_t    size,
  84.     byte_t        rsvd,
  85.     word32_t    length,
  86.     byte_t        param,
  87.     byte_t        control,
  88.     byte_t        rw,
  89.     bool_t        prnerr
  90. )
  91. {
  92.     UAGT_CAM_CCB    uagt;
  93.     CCB_SCSIIO    ccb;
  94.     byte_t        *cdb;
  95.  
  96.  
  97.     if ((pthru_fd < 0 && pthru_open(app_data.device) == FALSE) ||
  98.         scsipt_notrom_error)
  99.         return FALSE;
  100.  
  101.     memset(&uagt, 0, sizeof(uagt));
  102.     memset(&ccb, 0, sizeof(ccb));
  103.  
  104.     cdb = (byte_t *) ccb.cam_cdb_io.cam_cdb_bytes;
  105.  
  106.     /* Set up SCSI CDB */
  107.     switch (opcode & 0xf0) {
  108.     case 0xa0:
  109.     case 0xe0:
  110.         /* 12-byte commands */
  111.         cdb[0] = opcode;
  112.         cdb[1] = param;
  113.         cdb[2] = (addr >> 24) & 0xff;
  114.         cdb[3] = (addr >> 16) & 0xff;
  115.         cdb[4] = (addr >> 8) & 0xff;
  116.         cdb[5] = (addr & 0xff);
  117.         cdb[6] = (length >> 24) & 0xff;
  118.         cdb[7] = (length >> 16) & 0xff;
  119.         cdb[8] = (length >> 8) & 0xff;
  120.         cdb[9] = length & 0xff;
  121.         cdb[10] = rsvd;
  122.         cdb[11] = control;
  123.  
  124.         ccb.cam_cdb_len = 12;
  125.         break;
  126.  
  127.     case 0xc0:
  128.     case 0xd0:
  129.     case 0x20:
  130.     case 0x30:
  131.     case 0x40:
  132.         /* 10-byte commands */
  133.         cdb[0] = opcode;
  134.         cdb[1] = param;
  135.         cdb[2] = (addr >> 24) & 0xff;
  136.         cdb[3] = (addr >> 16) & 0xff;
  137.         cdb[4] = (addr >> 8) & 0xff;
  138.         cdb[5] = addr & 0xff;
  139.         cdb[6] = rsvd;
  140.         cdb[7] = (length >> 8) & 0xff;
  141.         cdb[8] = length & 0xff;
  142.         cdb[9] = control;
  143.  
  144.         ccb.cam_cdb_len = 10;
  145.         break;
  146.  
  147.     case 0x00:
  148.     case 0x10:
  149.         /* 6-byte commands */
  150.         cdb[0] = opcode;
  151.         cdb[1] = param;
  152.         cdb[2] = (addr >> 8) & 0xff;
  153.         cdb[3] = addr & 0xff;
  154.         cdb[4] = length & 0xff;
  155.         cdb[5] = control;
  156.  
  157.         ccb.cam_cdb_len = 6;
  158.         break;
  159.  
  160.     default:
  161.         if (app_data.scsierr_msg && prnerr)
  162.             fprintf(errfp, "0x%02x: Unknown SCSI opcode\n",
  163.                 opcode);
  164.         return FALSE;
  165.     }
  166.  
  167.     /* Setup the user agent ccb */
  168.     uagt.uagt_ccb = (CCB_HEADER *) &ccb;
  169.     uagt.uagt_ccblen = sizeof(CCB_SCSIIO);
  170.  
  171.     /* Setup the scsi ccb */
  172.     ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb;
  173.     ccb.cam_ch.cam_ccb_len = sizeof(CCB_SCSIIO);
  174.     ccb.cam_ch.cam_func_code = XPT_SCSI_IO;
  175.  
  176.     if (buf != NULL && size > 0) {
  177.         ccb.cam_ch.cam_flags |=
  178.             (rw == READ_OP) ? CAM_DIR_IN : CAM_DIR_OUT;
  179.         uagt.uagt_buffer = (u_char *) buf;
  180.         uagt.uagt_buflen = size;
  181.     }
  182.     else
  183.         ccb.cam_ch.cam_flags |= CAM_DIR_NONE;
  184.     
  185.     ccb.cam_ch.cam_flags |= CAM_DIS_AUTOSENSE;
  186.     ccb.cam_data_ptr = uagt.uagt_buffer;
  187.     ccb.cam_dxfer_len = uagt.uagt_buflen;
  188.     ccb.cam_timeout = 5;
  189.  
  190.     ccb.cam_ch.cam_path_id = bus;
  191.     ccb.cam_ch.cam_target_id = target;
  192.     ccb.cam_ch.cam_target_lun = lun;
  193.     
  194.     DBGDUMP("SCSI CDB bytes", cdb, ccb.cam_cdb_len);
  195.  
  196.     if (ioctl(pthru_fd, UAGT_CAM_IO, (caddr_t) &uagt) < 0) {
  197.         if (app_data.scsierr_msg && prnerr)
  198.             perror("UAGT_CAM_IO ioctl failed");
  199.  
  200.         pthru_close();
  201.         return FALSE;
  202.         }
  203.  
  204.     /* Check return status */
  205.     if ((ccb.cam_ch.cam_status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
  206.         if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN) {
  207.             memset(&ccb, 0, sizeof(ccb));
  208.             memset(&uagt, 0, sizeof(uagt));
  209.  
  210.             /* Setup the user agent ccb */
  211.             uagt.uagt_ccb = (CCB_HEADER  *) &ccb;
  212.             uagt.uagt_ccblen = sizeof(CCB_RELSIM);
  213.  
  214.             /* Setup the scsi ccb */
  215.             ccb.cam_ch.my_addr = (struct ccb_header *) &ccb;
  216.             ccb.cam_ch.cam_ccb_len = sizeof(CCB_RELSIM);
  217.             ccb.cam_ch.cam_func_code = XPT_REL_SIMQ;
  218.  
  219.             ccb.cam_ch.cam_path_id = bus;
  220.             ccb.cam_ch.cam_target_id = target;
  221.             ccb.cam_ch.cam_target_lun = lun;
  222.  
  223.             if (ioctl(pthru_fd, UAGT_CAM_IO, (caddr_t) &uagt) < 0) {
  224.                 pthru_close();
  225.                 return FALSE;
  226.             }
  227.         }
  228.  
  229.         if (app_data.scsierr_msg && prnerr) {
  230.             fprintf(errfp, "CD audio: %s %s:\n%s=0x%x %s=0x%x\n",
  231.                 "SCSI command fault on",
  232.                 app_data.device,
  233.                 "Opcode",
  234.                 opcode,
  235.                 "Status",
  236.                 ccb.cam_scsi_status);
  237.         }
  238.  
  239.         return FALSE;
  240.     }
  241.  
  242.     return TRUE;
  243. }
  244.  
  245.  
  246. /*
  247.  * pthru_open
  248.  *    Open SCSI pass-through device
  249.  *
  250.  * Args:
  251.  *    path - device path name string
  252.  *
  253.  * Return:
  254.  *    TRUE - open successful
  255.  *    FALSE - open failed
  256.  */
  257. bool_t
  258. pthru_open(char *path)
  259. {
  260.     struct stat    stbuf;
  261.     char        errstr[ERR_BUF_SZ];
  262.     int        i,
  263.             saverr,
  264.             ret;
  265.  
  266.     /* Check for validity of device node */
  267.     if (stat(path, &stbuf) < 0) {
  268.         sprintf(errstr, app_data.str_staterr, path);
  269.         cd_fatal_popup(app_data.str_fatal, errstr);
  270.         return FALSE;
  271.     }
  272.     if (!S_ISCHR(stbuf.st_mode)) {
  273.         sprintf(errstr, app_data.str_noderr, path);
  274.         cd_fatal_popup(app_data.str_fatal, errstr);
  275.         return FALSE;
  276.     }
  277.  
  278.     if ((pthru_fd = open(path, O_RDONLY | O_NDELAY, 0)) >= 0) {
  279.         struct devget    devget;
  280.  
  281.         if (ioctl(pthru_fd, DEVIOCGET, &devget) >= 0) {
  282. #ifdef __osf__
  283.             lun = devget.slave_num % 8;
  284.             devget.slave_num /= 8;
  285. #else
  286.             lun = 0;
  287. #endif
  288.             target = devget.slave_num % 8;
  289.             devget.slave_num /= 8;
  290.             bus = devget.slave_num % 8;
  291.             close(pthru_fd);
  292.  
  293.             if ((pthru_fd = open(DEV_CAM, O_RDWR, 0)) >= 0 ||
  294.                 (pthru_fd = open(DEV_CAM, O_RDONLY, 0)) >= 0) {
  295.  
  296.                 /* DEC hack:  The CAM driver allows
  297.                  * the open to succeed even if there
  298.                  * is no CD loaded.  We test for the
  299.                  * existence of a disc with
  300.                  * scsipt_tst_unit_rdy().
  301.                  */
  302.                 for (i = 0; i < 3; i++) {
  303.                     if ((ret = scsipt_tst_unit_rdy()) == TRUE)
  304.                     break;
  305.                 }
  306.                 if (!ret) {
  307.                     /* No CD loaded */
  308.                     pthru_close();
  309.                     return FALSE;
  310.                 }
  311.  
  312.                 return TRUE;
  313.             }
  314.  
  315.             DBGPRN(errfp, "Cannot open %s: errno=%d\n",
  316.                    DEV_CAM, errno);
  317.         }
  318.         else {
  319.             close(pthru_fd);
  320.  
  321.             DBGPRN(errfp,
  322.                    "DEVIOCGET ioctl failed on %s: errno=%d\n",
  323.                    path, errno);
  324.         }
  325.     }
  326.     else {
  327.         saverr = errno;
  328.         sprintf(errstr, "Cannot open %s: errno=%d", path, saverr);
  329.  
  330.         if (saverr != EIO)
  331.             cd_fatal_popup(app_data.str_fatal, errstr);
  332.  
  333.         DBGPRN(errfp, "%s\n", errstr);
  334.     }
  335.  
  336.     pthru_fd = bus = target = lun = -1;
  337.     return FALSE;
  338. }
  339.  
  340.  
  341. /*
  342.  * pthru_close
  343.  *    Close SCSI pass-through device
  344.  *
  345.  * Args:
  346.  *    Nothing.
  347.  *
  348.  * Return:
  349.  *    Nothing.
  350.  */
  351. void
  352. pthru_close(void)
  353. {
  354.     if (pthru_fd >= 0) {
  355.         close(pthru_fd);
  356.         pthru_fd = bus = target = lun = -1;
  357.     }
  358. }
  359.  
  360.  
  361. /*
  362.  * pthru_vers
  363.  *    Return OS Interface Module version string
  364.  *
  365.  * Args:
  366.  *    Nothing.
  367.  *
  368.  * Return:
  369.  *    Module version text string.
  370.  */
  371. char *
  372. pthru_vers(void)
  373. {
  374.     return ("OS Interface module (for DEC OSF/1 & Ultrix)\n");
  375. }
  376.  
  377. #endif    /* __alpha __osf__ ultrix __ultrix DI_SCSIPT DEMO_ONLY */
  378.  
  379.